package com.eastfair.venueservice.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.projectcore.enumeration.MenuAffiliationEnum;
import com.eastfair.venueservice.dao.ServiceBookingMapper;
import com.eastfair.venueservice.entity.*;
import com.eastfair.venueservice.enumeration.ServiceBookingReportSpaceStatusEnum;
import com.eastfair.venueservice.enumeration.ServiceOrderOrderStatusEnum;
import com.eastfair.venueservice.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.*;
import java.util.function.Consumer;

/**
 * 首页统计 service.
 *
 * @author dqq
 * @date 2023 /2/7
 */
@Service
@Slf4j
public class HomePageStatisticsServiceImpl implements HomePageStatisticsService {

    public static final DateTimeFormatter monthDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM");

    public static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Resource
    private ServiceProviderService serviceProviderService;

    @Resource
    private ServiceOrderService serviceOrderService;

    @Resource
    private ExhibitionManageService exhibitionManageService;

    @Resource
    private WorkOrderService workOrderService;

    @Resource
    private ServiceBookingMapper serviceBookingMapper;

    @Override
    public Map<String, Object> countItem() {
        int serviceProviderCount = countServiceProvider();
        int serviceOrderCount = countServiceOrder();
        Double transactionVolume = sumTransactionVolume();
        int exhibitionCount = countExhibition();
        int workOrderCount = countWorkOrder();
        Map<String, Object> map = new HashMap<>(16);
        map.put("serviceProviderCount", serviceProviderCount);
        map.put("serviceOrderCount", serviceOrderCount);
        map.put("transactionVolume", transactionVolume);
        map.put("exhibitionCount", exhibitionCount);
        map.put("workOrderCount", workOrderCount);
        return map;
    }

    @Override
    public int countServiceProvider() {
        QueryWrapper<ServiceProvider> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ServiceProvider::getIsDeleted, BusinessConstant.DELETE_NO)
        ;
        return serviceProviderService.count(queryWrapper);
    }

    @Override
    public int countServiceOrder() {
        QueryWrapper<ServiceOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ServiceOrder::getIsDeleted, BusinessConstant.DELETE_NO)
                .ne(ServiceOrder::getOrderStatus, ServiceOrderOrderStatusEnum.NOT_SUBMIT)
                .ne(ServiceOrder::getOrderStatus, ServiceOrderOrderStatusEnum.CANCEL)
        ;
        return serviceOrderService.count(queryWrapper);
    }

    @Override
    public Double sumTransactionVolume() {
        return null;
    }

    @Override
    public int countExhibition() {
        QueryWrapper<ExhibitionManage> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ExhibitionManage::getIsDeleted, BusinessConstant.DELETE_NO)
        ;
        return exhibitionManageService.count(queryWrapper);
    }

    @Override
    public int countWorkOrder() {
        QueryWrapper<WorkOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(WorkOrder::getIsDeleted, BusinessConstant.DELETE_NO);
        return workOrderService.count(queryWrapper);
    }

    @Override
    public List<Map<String, Object>> sumServiceCategoryFinance(Long exhibitionManageId) {
        QueryWrapper<ServiceBooking> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("sb.is_deleted", BusinessConstant.DELETE_NO)
                .eq("sb.provider_system", MenuAffiliationEnum.P_COMPOSITE_VENUE.getCode())
                .and(statusQueryWrapper -> statusQueryWrapper
                        .ne("sb.order_status", ServiceOrderOrderStatusEnum.NOT_SUBMIT.getCode())
                        .ne("sb.order_status", ServiceOrderOrderStatusEnum.CANCEL.getCode())
                        .or(reportSpaceStatusQueryWrapper -> reportSpaceStatusQueryWrapper.ne("sb.report_space_status", ServiceBookingReportSpaceStatusEnum.NOT_REPORTED.getCode())))
                .eq("sb.exhibition_manage_id", exhibitionManageId)
                .groupBy("sg.id")
        ;
        List<Map<String, Object>> list = serviceBookingMapper.sumServiceCategoryFinance(queryWrapper);
        return list;
    }

    @Override
    public List<String> listExhibitionManageDate(String month) {
        log.info("listExhibitionManageDate - 查询展会进行的日期, month={}", month);
        YearMonth yearMonth = YearMonth.parse(month, monthDateTimeFormatter);
        LocalDate endOfMonthLocalDate = yearMonth.atEndOfMonth();
        ZonedDateTime zonedDateTime = endOfMonthLocalDate.atStartOfDay(ZoneId.systemDefault());
        Date endOfMonthDate = Date.from(zonedDateTime.toInstant());
        // 输入月份的开始日期与结束日期
        String beginOfMonth = DateUtil.beginOfMonth(endOfMonthDate).toDateStr();
        String endOfMonth = DateUtil.endOfMonth(endOfMonthDate).toDateStr();
        LocalDate beginOfMonthLocalDate = LocalDate.parse(beginOfMonth, dateTimeFormatter);

        List<ExhibitionManage> list = listExhibitionManageByMonth(beginOfMonth, endOfMonth);
        TreeSet<LocalDate> exhibitionDateSet = new TreeSet<>(LocalDate::compareTo);
        for (ExhibitionManage exhibitionManage : list) {
            LocalDateTime arrangementStartTime = exhibitionManage.getArrangementStartTime();
            LocalDateTime arrangementEndTime = exhibitionManage.getArrangementEndTime();
            addExhibitionDateOfMonth(exhibitionDateSet, beginOfMonthLocalDate, endOfMonthLocalDate, arrangementStartTime, arrangementEndTime);

            LocalDateTime exhibitionStartTime = exhibitionManage.getExhibitionStartTime();
            LocalDateTime exhibitionEndTime = exhibitionManage.getExhibitionEndTime();
            addExhibitionDateOfMonth(exhibitionDateSet, beginOfMonthLocalDate, endOfMonthLocalDate, exhibitionStartTime, exhibitionEndTime);

            LocalDateTime dismantlingStartTime = exhibitionManage.getDismantlingStartTime();
            LocalDateTime dismantlingEndTime = exhibitionManage.getDismantlingEndTime();
            addExhibitionDateOfMonth(exhibitionDateSet, beginOfMonthLocalDate, endOfMonthLocalDate, dismantlingStartTime, dismantlingEndTime);
        }
        List<String> dateList = new ArrayList<>();
        for (LocalDate localDate : exhibitionDateSet) {
            String dateString = localDate.format(dateTimeFormatter);
            dateList.add(dateString);
        }
        return dateList;
    }

    @Override
    public List<ExhibitionManage> listExhibitionManageByMonth(String beginDate, String endDate) {
        log.info("listExhibitionManageByMonth - 按月份查询展会列表, beginDate={}, endDate={}", beginDate, endDate);
        // 查询本月的展会列表
        QueryWrapper<ExhibitionManage> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ExhibitionManage::getIsDeleted, BusinessConstant.DELETE_NO)
                .and(dateQueryWrapper ->
                        dateQueryWrapper
                                .between(ExhibitionManage::getArrangementStartTime, beginDate, endDate)
                                .or()
                                .between(ExhibitionManage::getArrangementEndTime, beginDate, endDate)
                                .or()
                                .between(ExhibitionManage::getDismantlingStartTime, beginDate, endDate)
                                .or()
                                .between(ExhibitionManage::getDismantlingEndTime, beginDate, endDate)
                                .or()
                                .between(ExhibitionManage::getExhibitionStartTime, beginDate, endDate)
                                .or()
                                .between(ExhibitionManage::getExhibitionEndTime, beginDate, endDate))
        ;
        List<ExhibitionManage> list = exhibitionManageService.list(queryWrapper);
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        return list;
    }

    private void addExhibitionDateOfMonth(Set<LocalDate> dateSet,  LocalDate beginOfMonthLocalDate, LocalDate endOfMonthLocalDate, LocalDateTime beginTime, LocalDateTime endTime) {
        if (beginTime == null || endTime == null) {
            return;
        }
        if (beginTime.isAfter(endTime)) {
            return;
        }
        LocalDate beginDate = beginTime.toLocalDate();
        LocalDate endDate = endTime.toLocalDate();
        while (beginDate.isBefore(endDate) || beginDate.equals(endDate)) {
            if (beginDate.isBefore(beginOfMonthLocalDate) || beginDate.isAfter(endOfMonthLocalDate)) {
                beginDate = beginDate.plusDays(1);
                continue;
            }
            dateSet.add(beginDate);
            beginDate = beginDate.plusDays(1);
        }
    }
}